#ifndef ZSPACE_H
#define ZSPACE_H

#include "preheader.h"

/**
    @file zspace.h
    @brief Perform the numerial space mass parallel calculations on the GPU.
    @author Claus Wimmer
    @date 2014-01-04

    Project: secondspace
    Licence: LGPL (Lesser GPL)
*/
class ZSpace : public QObject {

    Q_OBJECT

public:

    /**
        @brief Constructor. Init the GPU.
        @author Claus Wimmer
        @date 2012-10-05
        @param parent The main application window.
    */
    explicit ZSpace(QWidget *parent = 0);
    
    /**
        @brief Free memory and GPU.
        @author Claus Wimmer
        @date 2012-10-05
    */
    ~ZSpace();

    /**
        @brief Image with excitations of the space.
        @author Claus Wimmer
        @date 2012-10-05
        @return Pointer to the image. Will not change during program run.
    */
    QImage *image();

    /**
        @brief Error message handler according to KHRONOS spec.
        @author Claus Wimmer
        @date 2012-10-05
        @param _errInfo Textual message.
        @param cb Size of the info.

        Other params not used.
    */
    static void CL_CALLBACK contextCallback(const char *_errInfo, const void *, size_t cb, void *);

signals:
    
    /**
        @brief Raise display of a new space excitation image.
        @author Claus Wimmer
        @date 2012-10-05
    */
    void imageReady();

public slots:

    /**
        @brief Perform four new space calculation steps.
        @author Claus Wimmer
        @date 2012-10-05
    */
    void stepSpace();

    /**
        @brief Notify the kernels about the user interaction.
        @author Claus Wimmer
        @date 2012-10-05
        @param value Value of the slider.
    */
    void sliderValueChanged(int value);

    /**
        @brief Call the init kernel.
        @author Claus Wimmer
        @date 2012-10-05
    */
    void initSpace();

    /**
        @brief Notify the kernels about the user interaction.
        @author Claus Wimmer
        @date 2012-10-05
        @param x Mouse position.
        @param y Mouse position.
    */
    void mousePointed(uint x, uint y);
    
private:

    /**
        @brief Free memory and GPU.
        @author Claus Wimmer
        @date 2012-10-05
    */
    void cleanup();

    /**
        @brief Number of rows * number of columns in the space.
        @author Claus Wimmer
        @date 2012-10-05
        @return Size of the space in PIXELS.
    */
    uint points() const;

    /**
        @brief Display error message and exit if there is an error.
        @author Claus Wimmer
        @date 2012-10-05
        @param _err Number of the error or zero if there is no one.
        @param _name Verbose error message.
    */
    void checkErr(cl_int _err, const char *_name);

    // Data member area.

    /**
        @brief Array of Pixels which the image holds as data source.
        @author Claus Wimmer
        @date 2012-10-05

        Data modified by this class but never by the image.
    */
    cl_uchar *_imgData;

    /**
        @brief Image which shows the excitation of the space.
        @author Claus Wimmer
        @date 2012-10-05
    */
    QImage _image;

    /**
        @brief Space related PIXELS. Every pixel holds 8 float numbers.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_float *_spaceData;

    /**
        @brief Space PIXEL related flags (at least 32 bit).
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_int *_spaceBits;

    /**
        @brief Return value of KHRONOS api functions.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_int _errNum;

    /**
        @brief Value of the user control. Copied to the kernel.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_int _slider;

    /**
        @brief Error messages created during just-in-time kernel compilation.
        @author Claus Wimmer
        @date 2012-10-05
    */
    char _buildlog[16384];

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint _numPlatforms;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint _numDevices;

    /**
        @brief Helper variable.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint _idx;

    /**
        @brief Lines of the space.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint _rows;

    /**
        @brief Columns of the space.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint _cols;

    /**
        @brief Layers of the space.
        @author Claus Wimmer
        @date 2013-07-16
      */
    cl_uint _layers;

    /**
        @brief Float variables in one pixel.
        @author Claus Wimmer
        @date 2013-07-16
      */
    cl_uint _varsiz;

    /**
        @brief Current step count.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint _step;

    /**
        @brief Mouse position (Array with 2 members).
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_uint *_mouse;

    /**
        @brief Rendering modus.
        @author Claus Wimmer
        @date 2014-01-04
        */
    cl_uint _modus;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    size_t _global_work_group_size;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    size_t _max_work_group_size;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    size_t _local_work_group_size;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_platform_id *_platformIds;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_device_id *_deviceIDs;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_context _context;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_command_queue _queue;

    /**
        @brief See KHRONOS api. Init kernel.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_program _prog_init;

    /**
        @brief See KHRONOS api. Step kernel.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_program _prog_step;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_kernel _kern_init;

    /**
        @brief See KHRONOS api.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_kernel _kern_step;

    /**
        @brief Copy buffer for the space data.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_mem _mem_spaceData;

    /**
        @brief Copy buffer for the space bits.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_mem _mem_spaceBits;

    /**
        @brief Copy buffer for the image pixel data.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_mem _mem_imgData;

    /**
        @brief Copy buffer for the current space calculation step.
        @author Claus Wimmer
        @date 2012-10-05

        Must count every enqueue to ensure double-buffering in the kernel.
    */
    cl_mem _mem_step;

    /**
        @brief Copy buffer for the slider position.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_mem _mem_slider;

    /**
        @brief Copy buffer for the mouse click position.
        @author Claus Wimmer
        @date 2012-10-05
    */
    cl_mem _mem_mouse;

    /**
        @brief Rendering modus.
        @author Claus Wimmer
        @date 2014-01-04
      */
    cl_mem _mem_modus;

    /**
        @brief Include directive as content of the init kern program.
        @author Claus Wimmer
        @date 2013-07-26
      */
    static const char* _kern_init_prog;

    /**
       @brief Include directive as content of the step kern program.
       @author Claus Wimmer
       @date 2013-07-26
      */
    static const char* _kern_step_prog;

};
#endif // ZSPACE_H
